package cn.iocoder.yudao.module.eval.service.plan;

import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.eval.controller.admin.plan.vo.EvalPlanPageReqVO;
import cn.iocoder.yudao.module.eval.controller.admin.plan.vo.EvalPlanSaveReqVO;
import cn.iocoder.yudao.module.eval.dal.dataobject.plan.EvalPlanDO;
import cn.iocoder.yudao.module.eval.dal.mysql.plan.EvalPlanMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.eval.enums.ErrorCodeConstants.*;

/**
 * 评价计划 Service 实现类
 *
 * @author 芋道源码
 */
@Service
@Validated
@Slf4j
public class EvalPlanServiceImpl implements EvalPlanService {

    @Resource
    private EvalPlanMapper planMapper;

    @Override
    public Long createPlan(EvalPlanSaveReqVO createReqVO) {
        log.info("接收到创建计划请求: {}", createReqVO);
        log.info("计划编码: [{}]", createReqVO.getPlanCode());

        // 如果计划编码为空，自动生成
        if (StrUtil.isBlank(createReqVO.getPlanCode())) {
            String newPlanCode = generatePlanCode();
            log.info("自动生成计划编码: {}", newPlanCode);
            createReqVO.setPlanCode(newPlanCode);
        }

        // 校验计划编码唯一性
        validatePlanCodeUnique(null, createReqVO.getPlanCode());

        // 插入
        EvalPlanDO plan = BeanUtils.toBean(createReqVO, EvalPlanDO.class);
        planMapper.insert(plan);
        // 返回
        return plan.getId();
    }

    @Override
    public void updatePlan(EvalPlanSaveReqVO updateReqVO) {
        // 校验存在
        validatePlanExists(updateReqVO.getId());
        // 校验计划编码唯一性
        validatePlanCodeUnique(updateReqVO.getId(), updateReqVO.getPlanCode());

        // 更新
        EvalPlanDO updateObj = BeanUtils.toBean(updateReqVO, EvalPlanDO.class);
        planMapper.updateById(updateObj);
    }

    @Override
    public void deletePlan(Long id) {
        // 校验存在
        validatePlanExists(id);
        // 删除
        planMapper.deleteById(id);
    }

    private void validatePlanExists(Long id) {
        if (planMapper.selectById(id) == null) {
            throw exception(PLAN_NOT_EXISTS);
        }
    }

    private void validatePlanCodeUnique(Long id, String planCode) {
        EvalPlanDO plan = planMapper.selectByPlanCode(planCode);
        if (plan == null) {
            return;
        }
        // 如果 id 为空，说明不用比较是否为相同 id 的计划
        if (id == null) {
            throw exception(PLAN_CODE_DUPLICATE);
        }
        if (!plan.getId().equals(id)) {
            throw exception(PLAN_CODE_DUPLICATE);
        }
    }

    @Override
    public EvalPlanDO getPlan(Long id) {
        return planMapper.selectById(id);
    }

    @Override
    public List<EvalPlanDO> getPlanList(Collection<Long> ids) {
        return planMapper.selectBatchIds(ids);
    }

    @Override
    public PageResult<EvalPlanDO> getPlanPage(EvalPlanPageReqVO pageReqVO) {
        return planMapper.selectPage(pageReqVO);
    }

    @Override
    public EvalPlanDO getPlanByCode(String planCode) {
        return planMapper.selectByPlanCode(planCode);
    }

    @Override
    public List<EvalPlanDO> getPlanListByStatus(Integer planStatus) {
        return planMapper.selectListByStatus(planStatus);
    }

    @Override
    public List<EvalPlanDO> getPlanListByStatuses(Collection<Integer> planStatuses) {
        return planMapper.selectListByStatuses(planStatuses);
    }

    @Override
    public List<EvalPlanDO> getPlanListByProfessionId(Long professionId) {
        return planMapper.selectListByProfessionId(professionId);
    }

    @Override
    public void updatePlanStatus(Long id, Integer planStatus) {
        // 校验存在
        validatePlanExists(id);

        // 更新状态
        EvalPlanDO updateObj = new EvalPlanDO();
        updateObj.setId(id);
        updateObj.setPlanStatus(planStatus);
        planMapper.updateById(updateObj);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long copyPlan(Long id, String newPlanName, String newPlanCode) {
        // 校验原计划存在
        validatePlanExists(id);
        EvalPlanDO originalPlan = planMapper.selectById(id);
        
        // 校验新计划编码唯一性
        validatePlanCodeUnique(null, newPlanCode);

        // 复制计划
        EvalPlanDO newPlan = BeanUtils.toBean(originalPlan, EvalPlanDO.class);
        newPlan.setId(null);
        newPlan.setPlanName(newPlanName);
        newPlan.setPlanCode(newPlanCode);
        newPlan.setPlanStatus(0); // 设置为草稿状态
        planMapper.insert(newPlan);

        return newPlan.getId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> batchCreatePlans(EvalPlanSaveReqVO createReqVO, Integer batchCount) {
        List<Long> planIds = new ArrayList<>();
        
        for (int i = 1; i <= batchCount; i++) {
            String batchPlanCode = createReqVO.getPlanCode() + "-" + String.format("%03d", i);
            String batchPlanName = createReqVO.getPlanName() + "-第" + i + "批";
            
            // 校验计划编码唯一性
            validatePlanCodeUnique(null, batchPlanCode);
            
            // 创建计划
            EvalPlanDO plan = BeanUtils.toBean(createReqVO, EvalPlanDO.class);
            plan.setPlanCode(batchPlanCode);
            plan.setPlanName(batchPlanName);
            plan.setBatchName("第" + i + "批");
            planMapper.insert(plan);
            
            planIds.add(plan.getId());
        }
        
        return planIds;
    }

    @Override
    public void submitPlanForApproval(Long id) {
        // 校验存在
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            throw exception(PLAN_NOT_EXISTS);
        }

        // 校验状态
        if (!plan.getPlanStatus().equals(0)) { // 只有草稿状态才能提交
            throw exception(PLAN_STATUS_NOT_ALLOW_UPDATE);
        }

        // 更新状态
        updatePlanStatus(id, 1); // 已提交
    }

    @Override
    public void approvePlan(Long id, Boolean approved, String comments) {
        // 校验存在
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            throw exception(PLAN_NOT_EXISTS);
        }

        // 校验状态
        if (!plan.getPlanStatus().equals(1)) { // 只有已提交状态才能审批
            throw exception(PLAN_STATUS_NOT_ALLOW_UPDATE);
        }

        // 更新状态
        Integer newStatus = approved ? 2 : 0; // 审批通过或退回草稿
        updatePlanStatus(id, newStatus);

        // TODO: 记录审批日志
        log.info("计划审批：planId={}, approved={}, comments={}", id, approved, comments);
    }

    @Override
    public void publishPlan(Long id) {
        // 校验存在
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            throw exception(PLAN_NOT_EXISTS);
        }

        // 校验状态
        if (!plan.getPlanStatus().equals(2)) { // 只有已审批状态才能发布
            throw exception(PLAN_STATUS_NOT_ALLOW_UPDATE);
        }

        // 更新状态
        updatePlanStatus(id, 3); // 已发布
    }

    @Override
    public void startEvaluation(Long id) {
        // 校验存在
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            throw exception(PLAN_NOT_EXISTS);
        }

        // 校验状态
        if (!plan.getPlanStatus().equals(3)) { // 只有已发布状态才能开始
            throw exception(PLAN_STATUS_NOT_ALLOW_UPDATE);
        }

        // 更新状态
        updatePlanStatus(id, 4); // 进行中
    }

    @Override
    public void completeEvaluation(Long id) {
        // 校验存在
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            throw exception(PLAN_NOT_EXISTS);
        }

        // 校验状态
        if (!plan.getPlanStatus().equals(4)) { // 只有进行中状态才能完成
            throw exception(PLAN_STATUS_NOT_ALLOW_UPDATE);
        }

        // 更新状态
        updatePlanStatus(id, 5); // 已完成
    }

    @Override
    public void cancelPlan(Long id, String reason) {
        // 校验存在
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            throw exception(PLAN_NOT_EXISTS);
        }

        // 校验状态（已完成的计划不能取消）
        if (plan.getPlanStatus().equals(5)) {
            throw exception(PLAN_STATUS_NOT_ALLOW_UPDATE);
        }

        // 更新状态
        updatePlanStatus(id, 6); // 已取消

        // TODO: 记录取消原因
        log.info("计划取消：planId={}, reason={}", id, reason);
    }

    @Override
    public Object getPlanStatistics(Long id) {
        // TODO: 实现计划统计信息获取
        // 包括参评人数、科目数量、完成进度等
        return new java.util.HashMap<String, Object>() {{
            put("planId", id);
            put("candidateCount", 0);
            put("subjectCount", 0);
            put("completionRate", 0.0);
        }};
    }

    @Override
    public boolean canDeletePlan(Long id) {
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            return false;
        }

        // 只有草稿状态的计划可以删除
        return plan.getPlanStatus().equals(0);
    }

    @Override
    public boolean canUpdatePlan(Long id) {
        EvalPlanDO plan = getPlan(id);
        if (plan == null) {
            return false;
        }

        // 草稿和已提交状态的计划可以修改
        return plan.getPlanStatus().equals(0) || plan.getPlanStatus().equals(1);
    }

    /**
     * 生成计划编码
     * 格式：PLAN-YYYYMMDD-HHMMSS
     */
    private String generatePlanCode() {
        LocalDateTime now = LocalDateTime.now();
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd-HHmmss");
        return "PLAN-" + now.format(formatter);
    }

}
